use std::{sync::{mpsc, Arc, Mutex}, thread, time};

pub fn run(){
    println!("-----thread_pool-----");

    let pool = ThreadPool::new(5);
    pool.execute(||{
        println!("hello world threadName:{}", thread::current().name().unwrap());
    });
    pool.execute(||{
        thread::sleep(time::Duration::from_secs(3));
        println!("hello world 3 threadName:{}", thread::current().name().unwrap());
    });
    pool.execute(||{
        thread::sleep(time::Duration::from_secs(1));
        println!("hello world 1 threadName:{}", thread::current().name().unwrap());
    });
    pool.execute(||{
        thread::sleep(time::Duration::from_secs(1));
        println!("hello world 1 threadName:{}", thread::current().name().unwrap());
    });
    pool.execute(||{
        thread::sleep(time::Duration::from_secs(2));
        println!("hello world 2 threadName:{}", thread::current().name().unwrap());
    });
    pool.execute(||{
        thread::sleep(time::Duration::from_secs(1));
        println!("hello world 1 threadName:{}", thread::current().name().unwrap());
    });

    thread::sleep(time::Duration::from_secs(5));
    println!("-----thread_pool end-----")
}

type Job = Box<dyn FnOnce() + Send + 'static>;
struct ThreadPool{
    threads: Vec<Worker>,
    num: u32,
    sender: mpsc::Sender<Job>
}

impl ThreadPool{
    pub fn new(num: u32) -> ThreadPool{
        assert!(num > 0);

        let (tx,rx) = mpsc::channel();
        let rx = Arc::new(Mutex::new(rx));

        let mut threads = Vec::with_capacity(num as usize);
        for i in 0..num as usize{
            let rx = rx.clone();
            let w = Worker::new(i, rx);
            threads.push(w);
        }

        ThreadPool{threads, num, sender: tx}
    }

    pub fn execute<F>(&self,f :F) 
        where F: FnOnce() + Send + 'static{
            self.sender.send(Box::new(f)).unwrap();
    }
}
struct Worker{
    id: usize,
    thread: Option<std::thread::JoinHandle<()>>
}
impl Worker{
    pub fn new(id: usize, rx: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker{
        let closure = move ||{
            println!("Worker {} started", id);
            // 这里不能使用 while let Some(_)= rx.lock().unwrap().recv(){..}，
            // 因为 lock()获取的 MutexGurad 对象在 任务执行完毕之后才会释放，这期间会一直锁住receiver导致变成单线程
            loop{
                let job_o = rx.lock().unwrap().recv();
                match job_o{
                    Ok(job)=> job(),
                    Err(e) => {
                        println!("Worker {} received an error: {:?}", id, e);
                        break;
                    }
                }
            }
        };
        let handle = thread::Builder::new()
            .name(format!("pool-{}", id)) // 使用 format! 宏进行字符串拼接
            .spawn(closure)
            .expect("failed to spawn thread");

        Worker{id, thread: Some(handle)}
    }
}